/**
 * Created on 2007-03-06 23:13
 */
package game;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import game.media.MediaManager;
import game.media.audio.Sound;
import game.media.gfx.RenderManager;
import game.media.gfx.SquareEntity;

/**
 * @author David Wallin
 */
public final class Block extends BlockComponent
{
	private BasicMatris						m_BlockShape;
	private Matris							m_Matris;
	private BlockManager					m_BlockManager;
	private ArrayList<BlockComponent>		m_BlockComponents;
	private Sound							m_LandingSound;
	private Color							m_Color;
	
	private Settings						m_Settings;
	
	/**
	 * Constructor, initializes members
	 * 
	 * @param x The x coordinate of this Block in a matris unknown to it
	 * @param y The y coordinate of this Block in a matris unknown to it
	 * @param blockShape The layout of this Block's BlockPart:s
	 */
	public Block(int x, int y, BasicMatris blockShape, Color color, Matris matris, BlockManager manager)
	{
		super(x, y);
		
		m_BlockShape = blockShape;
		m_Matris = matris;
		m_BlockComponents = new ArrayList<BlockComponent>();
		m_LandingSound = MediaManager.INSTANCE.getAudioClip(MediaManager.SOUND_LAND);
		m_Color = color;
		m_Settings = Settings.INSTANCE;
		
		RenderManager renderManager = RenderManager.INSTANCE;
		
		for(int matrisY = 0; matrisY < m_BlockShape.getHeight(); matrisY++)
		{
			for(int matrisX = 0; matrisX < m_BlockShape.getWidth(); matrisX++)
			{
				if(m_BlockShape.getPosition(matrisX, matrisY))
				{
					m_BlockComponents.add(new BlockPart(x + matrisX, y + matrisY, matris,
							new SquareEntity(((x + matrisX) * renderManager.getSquareEntityWidth()) + matris.getXpos(),
									((y + matrisY) * renderManager.getSquareEntityHeight()) + matris.getYpos(),
									renderManager.getSquareEntityWidth(),
									renderManager.getSquareEntityHeight(),
									color,
									true)));
				}
			}
		}
		
		m_BlockManager = manager;
	}
	
	public void display(boolean display)
	{
		Iterator<BlockComponent> it = m_BlockComponents.iterator();
		
		while(it.hasNext())
		{
			it.next().display(display);
		}
	}
	
	public void setPosition(int matrisXpos, int matrisYpos)
	{
		if(m_Matris.checkSpace(matrisXpos, matrisYpos, m_BlockShape))
		{
			setMatrisXpos(matrisXpos);
			setMatrisYpos(matrisYpos);
		}
		else
		{
			//if the movement that failed was in y-axis, we should register the shape in the main matrix
			//and check for full lines, and remove these
			if(matrisYpos > getMatrisYpos())
			{
				m_LandingSound.play(false);
				m_LandingSound.play(true);
				
				try
				{
					m_BlockManager.setBlockToNull(this);
				}
				catch(IllegalArgumentException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	public void setMatrisXpos(int matrisXpos)
	{
		super.setMatrisXpos(matrisXpos);
		
		forcePosition(matrisXpos, getMatrisYpos());
	}
	
	public void setMatrisYpos(int matrisYpos)
	{
		super.setMatrisYpos(matrisYpos);
		
		forcePosition(getMatrisXpos(), matrisYpos);
	}
	
	public void setMatris(Matris matris)
	{
		m_Matris = matris;
		Iterator<BlockComponent> it = m_BlockComponents.iterator();
		
		while(it.hasNext())
		{
			it.next().setMatris(matris);
		}
	}
	
	/**
	 * Rotates the block 90 degrees counter clockwise, or clock wise, if
	 * reverse flip is set in settings
	 */
	public void rotate()
	{
		//the old height becomes the new width, and vice versa
		BasicMatris shape90 = new BasicMatris(m_BlockShape.getHeight(), m_BlockShape.getWidth());
		int matrisXpos = 0;
		int matrisYpos = 0;
		
		if(m_Settings.getReversedFlip())
		{
			//y transforms into x as x = width - y
			//x transforms into y as y = x
			int blockShapeWidth = m_BlockShape.getWidth();
			int blockShapeHeight = m_BlockShape.getHeight();
			int shape90Width = shape90.getWidth();
			
			for(int y = 0; y < blockShapeHeight; y++)
			{
				for(int x = 0; x < blockShapeWidth; x++)
				{
					boolean positionState = m_BlockShape.getPosition(x, y);
					shape90.setPosition((shape90Width - 1) - y, x, positionState);
				}
			}
			
			matrisXpos = getMatrisXpos();
			matrisYpos = getMatrisYpos();
			int offsetX = 1;
			int offsetY = -1;
			
			if(blockShapeHeight > blockShapeWidth)
			{
				offsetX = -1;
				offsetY = 1;
			}
			
			matrisXpos += offsetX;
			matrisYpos += offsetY;
		}
		else
		{
			//y transforms into x as x = y
			//x transforms into y as y = height - x
			int blockShapeWidth = m_BlockShape.getWidth();
			int blockShapeHeight = m_BlockShape.getHeight();
			int shape90Height = shape90.getHeight();
			
			for(int y = 0; y < blockShapeHeight; y++)
			{
				for(int x = 0; x < blockShapeWidth; x++)
				{
					boolean positionState = m_BlockShape.getPosition(x, y);
					shape90.setPosition(y, (shape90Height - 1) - x, positionState);
				}
			}
			
			matrisXpos = getMatrisXpos();
			matrisYpos = getMatrisYpos();
			int offsetX = 1;
			int offsetY = -1;
			
			if(blockShapeHeight > blockShapeWidth)
			{
				offsetX = -1;
				offsetY = 1;
			}
			
			matrisXpos += offsetX;
			matrisYpos += offsetY;
		}
		
		if(m_Matris.checkSpace(matrisXpos, matrisYpos, shape90))
		{
			setMatrisXpos(matrisXpos);
			setMatrisYpos(matrisYpos);
			m_BlockShape = shape90;
		}
	}
	
	public boolean hasPosition(int x, int y)
	{
		return m_BlockShape.getPosition(x - getMatrisXpos(), y - getMatrisYpos());
	}
	
	public int getWidth()
	{
		return m_BlockShape.getWidth();
	}
	
	public int getHeight()
	{
		return m_BlockShape.getHeight();
	}
	
	public int getXpos()
	{
		return (m_Matris.getXpos() + (this.getMatrisXpos() * m_RenderManager.getSquareEntityWidth()));
	}
	
	public int getYpos()
	{
		return (m_Matris.getYpos() + (this.getMatrisYpos() * m_RenderManager.getSquareEntityHeight()));
	}
	
	public Color getColor()
	{
		return m_Color;
	}
	
	public BasicMatris getBlockShape()
	{
		return m_BlockShape;
	}
	
	public Collection<BlockComponent> getBlockComponents()
	{
		return m_BlockComponents;
	}
	
	public void setState(States state)
	{
		Iterator<BlockComponent> it = m_BlockComponents.iterator();
		
		while(it.hasNext())
		{
			it.next().setState(state);
		}
	}
	
	private void forcePosition(int matrisXpos, int matrisYpos)
	{
		Iterator<BlockComponent> it = m_BlockComponents.iterator();
		
		for(int y = 0; y < m_BlockShape.getHeight(); y++)
		{
			for(int x = 0; x < m_BlockShape.getWidth(); x++)
			{
				if(m_BlockShape.getPosition(x, y))
				{
					if(it.hasNext())
					{
						BlockComponent block = it.next();
						
						block.setMatrisXpos(matrisXpos + x);
						block.setMatrisYpos(matrisYpos + y);
					}
				}
			}
		}
	}
}
